package com.fengxu.gamescript.data

import com.alibaba.fastjson.JSONObject
import com.fengxu.gamescript.data.po.User
import com.fengxu.gamescript.data.vo.Result
import com.fengxu.gamescript.jsengine.core.JsRuntime
import com.fengxu.gamescript.jsengine.core.JsRunnerLog
import com.fengxu.gamescript.provide.ProviderFactory
import org.jetbrains.anko.doAsync
import java.lang.IllegalStateException
import java.lang.UnsupportedOperationException
import java.security.Provider
import java.util.*
import kotlin.collections.LinkedHashMap
import kotlin.properties.Delegates

/**
 * 全局数据
 */
object GlobalData {

    // 登陆用户信息
    var user: User? = null

    // 存放脚本的文件夹名称, 存放于 内部储存/Android/data/包名/files/...
    val MusicScriptFolderName = "MusicScript"

    // 存放脚本的文件夹全路径
    var MusicScriptFolderPath: String by Delegates.notNull()

    // 存放当前所有正在执行的脚本, 名称->JsRunner,只能从主线程中操纵
    private var JsRunningMap = LinkedHashMap<String, JsRuntime>()

    // 正在运行js脚本数量改变时触发
    val jsRunningMapChanged: MutableList<(ScriptRunNumChangeType,String)->Unit> = mutableListOf()

    // 脚本运行发生错误时触发
    var jsRunningError:((name:String, info:String)->Unit)? = null

    // 存放所有执行过的日志
    private val JsRunnerLogList: Vector<JsRunnerLog> = Vector()

    // 设置日志改变事件
    var logChanged: MutableList<LogEvent> = mutableListOf()

    /**
     * 获取所有正在运行的脚本环境(不可修改)
     */
    fun getRunningScriptMap(): Map<String, JsRuntime>{
        if(Thread.currentThread().name != "main"){
            throw UnsupportedOperationException("不支持从非ui线程获取正在运行的脚本!")
        }
        val map: MutableMap<String, JsRuntime> = mutableMapOf()
        // 拷贝一份
        JsRunningMap.forEach { (k, v) ->
            map[k] = v
        }
        return map;
    }

    /**
     * 添加一个成功运行的脚本环境
     * @param runtime 脚本环境
     */
    fun addRunningScript(runtime: JsRuntime){
        if(Thread.currentThread().name != "main"){
            throw UnsupportedOperationException("不支持从非ui线程获取正在运行的脚本!")
        }
        JsRunningMap[runtime.name] = runtime
        jsRunningMapChanged.forEach { it.invoke(ScriptRunNumChangeType.Start, runtime.name) }
    }

    /**
     * 移除一个运行完毕的脚本环境
     * @param runtime 脚本环境
     */
    fun removeStopedScript(runtime: JsRuntime){
        if(!isMainThread()){
            throw UnsupportedOperationException("不支持从非ui线程获取正在运行的脚本!")
        }
        if(JsRunningMap.containsKey(runtime.name)){
            JsRunningMap.remove(runtime.name)
            jsRunningMapChanged.forEach { it.invoke(ScriptRunNumChangeType.Stop, runtime.name) }
        }
    }

    /**
     * 添加日志
     */
    fun addLog(log: JsRunnerLog){
        JsRunnerLogList.addElement(log)
        if(log.logLevel == JsRunnerLog.LogLevel.Error){
            // 触发错误事件
            jsRunningError?.invoke(log.name, log.msg)
        }
        logChanged.forEach { it.changed(LogChangeType.Add, log) }
    }

    /**
     * 获取日志列表
     */
    fun getLogList() : List<JsRunnerLog>{
        return listOf<JsRunnerLog>(*(JsRunnerLogList.toTypedArray()))
    }

    /**
     * 清空日志
     */
    fun clearAllLog(){
        JsRunnerLogList.clear()
        logChanged.forEach { it.changed(LogChangeType.Clear, null) }
    }

    /**
     * 判断当前线程是否是主线程
     */
    fun isMainThread():Boolean{
        return Thread.currentThread().name == "main";
    }
}

// 运行的脚本数量变化类型
enum class ScriptRunNumChangeType{
    Start,Stop
}

// 日志变化的类型
enum class LogChangeType{
    Add,Clear
}

interface LogEvent{
    fun changed(type: LogChangeType, log: JsRunnerLog?)
}